/**
 * Copyright 1998-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
 * All rights reserved.
 */
package ca.uvic.cs.cogz.mapping.filter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import ca.uvic.cs.cogz.mapping.core.AbstractMapElement;
import ca.uvic.cs.cogz.mapping.core.MappingTypeManager.MappingType;
import ca.uvic.cs.cogz.mapping.ui.MappingVisualizationPanel;
import edu.stanford.smi.protege.model.Frame;
import edu.stanford.smi.protege.model.KnowledgeBase;

/**
 * TODO : should remove all the duplication of source and target filters and have two static
 * instances of this class getInstance should accept the type that you want rather than using all
 * the active search index setting
 */

/**
 * Manages the different tree filters for the source and target ontologies.
 * 
 * @author Sean Falconer
 * @date 10-Jan-07
 */
public class TreeFilterManager {
	public enum TreeFilterType {
		TREE_SEARCH_FILTER("Tree search filter"), MAPPED_ITEM_FILTER("Mapped items filter"), FRAME_TO_MAPPINGS_FILTER("Frame to mappings filter"), FRAME_ITEM_FILTER("Frame filter");

		private String typeText;

		TreeFilterType(String typeText) {
			this.typeText = typeText;
		}

		public String toString() {
			return typeText;
		}
	}

	public static final int SOURCE_SEARCH = 0;
	public static final int TARGET_SEARCH = 1;

	private static TreeFilterManager treeSearchManager = null;

	/** arrays for supported source and target ontology filters */
	private TreeSearchFilter[] treeSearchFilters = new TreeSearchFilter[2];
	private MappedItemFilter[] mappedItemSearch = new MappedItemFilter[2];
	private FrameToMappingsItemFilter[] frameToMappingsItemSearch = new FrameToMappingsItemFilter[2];
	private FrameItemFilter[] frameFilters = new FrameItemFilter[2];

	/** list of all supported filters */
	private List<ITreeFilter> allFilters;
	private List<ITreeFilter> sourceFilters;
	private List<ITreeFilter> targetFilters;

	private int activeSearchIndex;

	private TreeFilterManager() {
		reset();
	}

	public static TreeFilterManager getInstance() {
		if (treeSearchManager == null) {
			treeSearchManager = new TreeFilterManager();
		}
		return treeSearchManager;
	}

	public void reset() {
		activeSearchIndex = SOURCE_SEARCH;
		allFilters = new ArrayList<ITreeFilter>();
		sourceFilters = new ArrayList<ITreeFilter>();
		targetFilters = new ArrayList<ITreeFilter>();

		for (int i = 0; i < treeSearchFilters.length; i++) {
			treeSearchFilters[i] = new TreeSearchFilter();
			allFilters.add(treeSearchFilters[i]);
		}
		for (int i = 0; i < mappedItemSearch.length; i++) {
			mappedItemSearch[i] = new MappedItemFilter();
			allFilters.add(mappedItemSearch[i]);
		}
		for (int i = 0; i < frameToMappingsItemSearch.length; i++) {
			frameToMappingsItemSearch[i] = new FrameToMappingsItemFilter();
			allFilters.add(frameToMappingsItemSearch[i]);
		}
		for (int i = 0; i < frameFilters.length; i++) {
			frameFilters[i] = new FrameItemFilter();
			allFilters.add(frameFilters[i]);
		}

		sourceFilters.add(treeSearchFilters[SOURCE_SEARCH]);
		sourceFilters.add(mappedItemSearch[SOURCE_SEARCH]);
		sourceFilters.add(frameToMappingsItemSearch[SOURCE_SEARCH]);
		sourceFilters.add(frameFilters[SOURCE_SEARCH]);

		targetFilters.add(treeSearchFilters[TARGET_SEARCH]);
		targetFilters.add(mappedItemSearch[TARGET_SEARCH]);
		targetFilters.add(frameToMappingsItemSearch[TARGET_SEARCH]);
		targetFilters.add(frameFilters[TARGET_SEARCH]);
	}

	public void resetSearch(int index) {
		if(index == SOURCE_SEARCH) resetSearch(sourceFilters);
		else resetSearch(targetFilters);
	}

	public void setActiveSearch(int activeSearchIndex) {
		this.activeSearchIndex = activeSearchIndex;
	}

	public boolean isTreeFilteringActive() {
		if (activeSearchIndex == SOURCE_SEARCH) {
			return isTreeFilteringActive(sourceFilters);
		}

		return isTreeFilteringActive(targetFilters);
	}

	public boolean isMappedItemSearchActive(int index) {
		return mappedItemSearch[index].isActive();
	}

	public MappingType getActiveMappingTypeFilter(int index) {
		return mappedItemSearch[index].getMappingType();
	}

	public boolean isFramePinned(int index, Frame frame) {
		return frameFilters[index].isPinned(frame);
	}

	public void removePinnedFrame(int index, Frame frame) {
		frameFilters[index].removePin(frame);
	}

	public String getSearchText(int filterIndex) {
		return treeSearchFilters[filterIndex].getSearchText();
	}

	public void resetFrameFilters() {
		frameFilters[activeSearchIndex].reset();
	}

	public boolean isMatch(Frame frame) {
		if (activeSearchIndex == SOURCE_SEARCH) {
			return isMatch(frame, sourceFilters);
		}

		return isMatch(frame, targetFilters);
	}

	@SuppressWarnings("unchecked")
	public Collection<Collection> performSearch(KnowledgeBase kb, String searchText) {
		TreeSearchFilter treeSearch = treeSearchFilters[activeSearchIndex];

		// make sure this is a new search
		if (searchText.equals(MappingVisualizationPanel.SEARCH_DEFAULT_TEXT_LABEL) || treeSearch.getSearchText().equals(searchText)) {
			return null;
		}

		treeSearch.setSearchText(searchText);

		return treeSearch.performSearch(kb);
	}

	@SuppressWarnings("unchecked")
	public Collection<Collection> performMapFilter(KnowledgeBase kb, MappingType mappingType) {
		MappedItemFilter mappedSearch = mappedItemSearch[activeSearchIndex];
		mappedSearch.setTreeIndex(activeSearchIndex);
		mappedSearch.setMappingType(mappingType);

		return mappedSearch.performSearch(kb);
	}

	@SuppressWarnings("unchecked")
	public Collection<Collection> performFrameToMapFilter(List<AbstractMapElement> mappings, Frame focusFrame) {
		FrameToMappingsItemFilter frameToMappedItemSearch = frameToMappingsItemSearch[activeSearchIndex];
		frameToMappedItemSearch.setTreeIndex(activeSearchIndex);
		frameToMappedItemSearch.setMappings(mappings);

		return frameToMappedItemSearch.performSearch(null);
	}

	public void performFrameFilter(Frame frameToFilter, boolean filterItem) {
		FrameItemFilter frameToMappedItemSearch = frameFilters[activeSearchIndex];
		if (filterItem) {
			frameToMappedItemSearch.addFilteredItem(frameToFilter);
		} else {
			frameToMappedItemSearch.addNonFilteredItem(frameToFilter);
		}
	}
	
	private void resetSearch(List<ITreeFilter> filters) {
		for (ITreeFilter filter : filters) {
			//if (filter instanceof MappedItemFilter || filter instanceof FrameItemFilter || filter instanceof FrameToMappingsItemFilter) {
				filter.reset();
			//}
		}
	}

	private boolean isMatch(Frame frame, List<ITreeFilter> filters) {
		for (ITreeFilter filter : filters) {
			if (filter.isMatch(frame)) {
				return true;
			}
		}

		return false;
	}

	private boolean isTreeFilteringActive(List<ITreeFilter> filters) {
		for (ITreeFilter filter : filters) {
			if (filter.isActive()) {
				return true;
			}
		}

		return false;
	}
}
